package hk.ust.comp3111.ustnutrition;

import hk.ust.comp3111.ustnutrition.data.DataAccessor;
import hk.ust.comp3111.ustnutrition.data.DataTableListener;
import hk.ust.comp3111.ustnutrition.data.db.IntakeRecord;
import hk.ust.comp3111.ustnutrition.data.db.User;
import hk.ust.comp3111.ustnutrition.formula.NutritionCalculator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint.Align;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.Fragment;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import com.jjoe64.graphview.BarGraphView;
import com.jjoe64.graphview.GraphViewDataInterface;
import com.jjoe64.graphview.GraphViewSeries;
import com.jjoe64.graphview.GraphViewSeries.GraphViewSeriesStyle;
import com.jjoe64.graphview.GraphViewStyle;
import com.jjoe64.graphview.ValueDependentColor;

public class MyProfileFragment extends Fragment implements DataTableListener<IntakeRecord>
{
	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container,
			Bundle savedInstanceState)
	{
		return inflater.inflate(R.layout.my_profile_frag, container, false);
	}

	@Override
	public void onActivityCreated(Bundle savedInstanceState)
	{
		super.onActivityCreated(savedInstanceState);
		initGraph();
		return;
	}
	
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		DataAccessor.Instance.getRecords().addChangeListener(this);
	}

	@Override
	public void onDestroy() {
		super.onDestroy();
		DataAccessor.Instance.getRecords().removeChangeListener(this);
	}

	private void initInfo()
	{
		TextView greeting = (TextView)getView().findViewById(R.id.greeting);
		greeting.setText("Hi, " + (mUser.getName().isEmpty() ? "User"
				: mUser.getName()) + "!");

		TextView suggestion = (TextView)getView().findViewById(R.id.suggestion);
		NutritionCalculator calc = new NutritionCalculator(mUser);
		calc.calc();
		double choRatio = nutritions[1] / calc.getCarbohydratesNeed();
		double proteinRatio = nutritions[2] / calc.getProteinNeed();
		double fatRatio = nutritions[3] / calc.getFatNeed();
		double sodiumRatio = nutritions[4] / calc.getSodiumNeed();
		if (choRatio < 0.5)
		{
			suggestion.setText("Checkout our carbohydrate-rich selections suggested just for you!");
		}
		else if (proteinRatio < 0.5)
		{
			suggestion.setText("Checkout our protein-rich selections suggested just for you!");
		}
		else if (fatRatio < 0.25)
		{
			suggestion.setText("Checkout our fat-rich selections suggested just for you!");
		}
		else if (sodiumRatio < 0.25)
		{
			suggestion.setText("Checkout our sodium-rich selections suggested just for you!");
		}
		else if (choRatio + proteinRatio + fatRatio + sodiumRatio <= 2.5)
		{
			suggestion.setText("Not bad, but checkout our balanced selections suggested just for you!");
		}
		else if (choRatio + proteinRatio + fatRatio + sodiumRatio <= 3.5)
		{
			suggestion.setText("Cool, but checkout our balanced selections suggested just for you!");
		}
		else if (choRatio + proteinRatio + fatRatio + sodiumRatio <= 4.0
				&& choRatio <= 1.1 && proteinRatio <= 1.1 && fatRatio <= 1.2
				&& sodiumRatio <= 1.2)
		{
			suggestion.setText("Shiny! You can remove our apps now!");
		}
		else
		{
			suggestion.setText("A bit too much, checkout our balanced selections suggested just for you!");
		}
	}

	private void initGraph()
	{
		graphView = new MyBarGraphView(getActivity(), "");
		graphView.setHorizontalLabels(new String[] {
				"Carbohydrate", "Protein", "Fat", "Sodium"});
		graphView.setVerticalLabels(new String[] {">150%", "100%", "50%", "0%"});
		graphView.setManualYAxisBounds(150, 0);
		graphView.setScrollable(false);

		GraphViewStyle graphStyle = graphView.getGraphViewStyle();
		graphStyle.setHorizontalLabelsColor(Color.BLACK);
		graphStyle.setVerticalLabelsColor(Color.BLACK);
		graphStyle.setTextSize(MiscUtils.dpToPx(getActivity(), 13));
		graphStyle.setVerticalLabelsAlign(Align.RIGHT);
		graphStyle.setVerticalLabelsWidth((int)MiscUtils.dpToPx(getActivity(),
				48));

	    int pad = (int)MiscUtils.dpToPx(getActivity(), 8);
	    graphView.setPadding(pad, pad, pad, pad);

		ViewGroup root = (ViewGroup)getView().findViewById(R.id.graph);
		root.addView(graphView);
		
		update();
	}
	
	double[] nutritions;
	
	private void update() {
		mUser = DataAccessor.Instance.getUser();
		
		NutritionCalculator calc = new NutritionCalculator(mUser);
		calc.calc();
		
		nutritions = mUser.getNutritions();
		initInfo();

		GraphViewData[] userData = new GraphViewData[4];
		userData[0] = new GraphViewData(0, Math.min(nutritions[1]
				/ calc.getCarbohydratesNeed(), 1.5) * 100);
		userData[1] = new GraphViewData(1, Math.min(nutritions[2]
				/ calc.getProteinNeed(), 1.5) * 100);
		userData[2] = new GraphViewData(2, Math.min(nutritions[3]
				/ calc.getFatNeed(), 1.5) * 100);
		userData[3] = new GraphViewData(3, Math.min(nutritions[4]
				/ calc.getSodiumNeed(), 1.5) * 100);

		GraphViewSeriesStyle seriesStyle = new GraphViewSeriesStyle();
		seriesStyle.setValueDependentColor(new ValueDependentColor()
				{
					@Override
					public int get(GraphViewDataInterface data)
					{
						if (data.getY() <= 100)
						{
							//double ratio = data.getY() / 100.0;
							//return Color.rgb(0, (int)(0xFF * ratio),
							//		(int)(0xFF * (1 - ratio)));
							return Color.rgb(0, 0, 0xFF);
						}
						else
						{
							double ratio = (data.getY() - 100) / 50.0;
							return Color.rgb((int)(0xFF * ratio),
									0, (int)(0xFF * (1 - ratio)));
						}
					}
				});
		
		GraphViewSeries series = new GraphViewSeries("series", seriesStyle,
				userData);
		graphView.removeAllSeries();
		graphView.addSeries(series);
	}

	public User getUser()
	{
		return DataAccessor.Instance.getUser();
	}

	private class MyBarGraphView extends BarGraphView
	{
		public MyBarGraphView(Context context, AttributeSet attrs) {
			super(context, attrs);
		}

		public MyBarGraphView(Context context, String title) {
			super(context, title);
		}

		@Override
		protected void drawHorizontalLabels(Canvas canvas, float border,
				float horstart, float height, String[] horlabels, float graphwidth) {
			// horizontal labels + lines
			paint.setTextAlign(Align.CENTER);

			int hors = horlabels.length;
			float barwidth = graphwidth/horlabels.length;
			float textOffset = barwidth/2;
			for (int i = 0; i < horlabels.length; i++) {
				// lines
				float x = ((graphwidth / hors) * i) + horstart;
				paint.setColor(0);
				canvas.drawLine(x, height - border, x, border, paint);

				// text
				x = barwidth*i + textOffset + horstart;
				paint.setColor(graphViewStyle.getHorizontalLabelsColor());
				canvas.drawText(horlabels[i], x, height - 4, paint);
			}
		}

		@Override
		public void drawSeries(Canvas canvas, GraphViewDataInterface[] values, float graphwidth, float graphheight,
				float border, double minX, double minY, double diffX, double diffY,
				float horstart, GraphViewSeriesStyle style) {
			float colwidth = graphwidth / (values.length);

			paint.setStrokeWidth(style.thickness);

			float offset = 0;

			NutritionCalculator calc = new NutritionCalculator(mUser);
			calc.calc();

			float dp4 = MiscUtils.dpToPx(getActivity(), 4);

			// draw data
			for (int i = 0; i < values.length; i++) {
				float valY = (float) (values[i].getY() - minY);
				float ratY = (float) (valY / diffY);
				float y = graphheight * ratY;

				// hook for value dependent color
				if (style.getValueDependentColor() != null) {
					paint.setColor(style.getValueDependentColor().get(values[i]));
				} else {
					paint.setColor(style.color);
				}

				float left = (i * colwidth) + horstart -offset;
				float top = (border - y) + graphheight;
				float right = ((i * colwidth) + horstart) + (colwidth - 1) -offset;
				canvas.drawRect(left, top, right, graphheight + border - 1, paint);

				top -= dp4;
				boolean isOver = false;
				boolean isOverflow = false;
				if (top <= border)
				{
					top += border + dp4;
					isOverflow = true;
					isOver = true;
				}
				else if (valY >= 100)
				{
					isOver = true;
				}
				paint.setTextAlign(Align.CENTER);
				switch (i)
				{
				case 0:
					paint.setColor(isOverflow ? Color.WHITE : Color.BLACK);
					canvas.drawText(String.format("%.1fg", nutritions[1]),
							(left+right)/2, top, paint);
					paint.setColor(isOver ? Color.WHITE : Color.BLACK);
					canvas.drawText(String.format("%.1fg",
							calc.getCarbohydratesNeed()), (left+right)/2,
							(graphheight / 3) + border - dp4, paint);
					break;

				case 1:
					paint.setColor(isOverflow ? Color.WHITE : Color.BLACK);
					canvas.drawText(String.format("%.1fg", nutritions[2]),
							(left+right)/2, top, paint);
					paint.setColor(isOver ? Color.WHITE : Color.BLACK);
					canvas.drawText(String.format("%.1fg",
							calc.getProteinNeed()), (left+right)/2,
							(graphheight / 3) + border - dp4, paint);
					break;

				case 2:
					paint.setColor(isOverflow ? Color.WHITE : Color.BLACK);
					canvas.drawText(String.format("%.1fg", nutritions[3]),
							(left+right)/2, top, paint);
					paint.setColor(isOver ? Color.WHITE : Color.BLACK);
					canvas.drawText(String.format("%.1fg",
							calc.getFatNeed()), (left+right)/2,
							(graphheight / 3) + border - dp4, paint);
					break;

				case 3:
					paint.setColor(isOverflow ? Color.WHITE : Color.BLACK);
					canvas.drawText(String.format("%.3fg", nutritions[4]),
							(left+right)/2, top, paint);
					paint.setColor(isOver ? Color.WHITE : Color.BLACK);
					canvas.drawText(String.format("%.3fg",
							calc.getSodiumNeed()), (left+right)/2,
							(graphheight / 3) + border - dp4, paint);
					break;
				}
			}
		}
	}

	private User mUser;
	BarGraphView graphView;

	Handler handler = new Handler();
	boolean dirty;
	
	@Override
	public void changed(DataTableListener.ChangeEvent<IntakeRecord> event) {
		dirty = true;
		handler.postDelayed(new Runnable() {
			@Override
			public void run() {
				if(dirty) {
					dirty = false;
					if (graphView != null) {
						update();
					}
				}
			}
		}, 500);
	}
}
